# ifndef __Types_H_
# define __Types_H_

//
// Types.h
//
// Declarations of types of map objects.
//

void InitTypes ();
void DestroyTypes ();

//////////////////////////////////////////

# include "RgnKind.h"
# include "PtAlgo.h"

class CTypeSet;

//
// Type set convertors.
//

typedef USHORT (* pfConvertTypeSet_t) (RGN_KIND _Kind, USHORT _ushType);

// INTERNAL USE ONLY.
struct CTypeSetConvertorInfo {
	const CTypeSet * const pTypeSetFrom;
	const CTypeSet * const pTypeSetTo;
	pfConvertTypeSet_t pfConvertTypeSet;

	static CTypeSetConvertorInfo * s_pFirst;
	CTypeSetConvertorInfo * m_pNext;

	CTypeSetConvertorInfo (pfConvertTypeSet_t _pfConvertTypeSet, const CTypeSet * _pTypeSetFrom, const CTypeSet * _pTypeSetTo) :
		pfConvertTypeSet (_pfConvertTypeSet),
		pTypeSetFrom (_pTypeSetFrom),
		pTypeSetTo (_pTypeSetTo)
	{
		// Insert to the head of the list.
		m_pNext = CTypeSetConvertorInfo::s_pFirst;
		CTypeSetConvertorInfo::s_pFirst = this;
	}
};

# define DECLARE_TYPESET_CONVERTOR(_pfConvert, _pTypeSetFrom, _pTypeSetTo) \
	static CTypeSetConvertorInfo _pfConvert##_T (_pfConvert, _pTypeSetFrom, _pTypeSetTo);

//
// Round coordinates to a specific grid.
//
struct map_t;
typedef float (* pfGetLatGrid_t)  (const map_t & _map, size_t _cLevelIdx);
typedef void  (* pfRoundPoint_t)  (const map_t & _map, size_t _cLevelIdx, point_t & _pt);
typedef void  (* pfRoundPoints_t) (const map_t & _map, size_t _cLevelIdx, points_t & _points);
typedef void  (* pfRoundRect_t)   (const map_t & _map, size_t _cLevelIdx, rect_t & _rect);

///////////////////////////////////////////

struct rgn_t;
typedef void (* pfPrepareLabel_t) (rgn_t & _rgn);
typedef void (* pfDrawLabel_t) (HDC _hDC, const rgn_t & _rgn);

extern const char * g_strKinds [];

///////////////////////////////////////////

typedef bool (* pfRgnPredicate_t) (const rgn_t & _rgn);

enum type_category_t {
	catRoads,
	catBoundaries,
	catElevation,
	catCities,
	catLabels,
	catFood,
	catLodging,
	catAttractions,
	catEntertainment,
	catShopping,
	catServices,
	catEmrgGov,
	catTransport,
	catReligion,
	catEducation,
	catSports,
	catRecreation,
	catWater,
	catLand,
	catManMade,
	catBuilding,
	catAuto,
	catAviation,
	catMarine,
	catMarineNavaids,
	catMarineDanger,
	catOthers,
	catUnknown,
};

const char * GetTypeCategoryDisplayName (type_category_t _tc);
COLORREF     GetTypeCategoryColor       (type_category_t _tc);


	//
	// The metainfo.
	//
struct type_desc_t {
	union {
		// Unique key for search.
		ULONG        ulType;

		struct {
			// Numeric code for the object type.
			USHORT   ushType;
			// See RGN_KIND for the allowed values.
			USHORT   Kind;
		};
	};
		// Maximum key value.
	ULONG            ulType2;

	type_category_t  Category;

		// English description of the type.
	const char *     strTypeName;

		// The brush to fill polygons.
	HBRUSH *         phBrush;

		// The pen to draw polylines.
	HPEN *           phPen;
		// The pen for second pass. NOTE: NULL means not to draw 2nd pass.
	HPEN *           phPen2;
		// The geometric pen used to output to printer.
	HPEN             hPenGeometric;

		// The font and color for labels. NOTE: NULL means default font.
	HFONT *          phFont;
	COLORREF         colText;

		// The icon for point/POI. NOTE: can't be NULL; use g_hcurUnknown for default.
	HCURSOR *        phCursor;

		// The function used to prepare object for label output.
	pfPrepareLabel_t pfPrepareLabel;
		// The function used for label output. NOTE: can't be NULL; use DrawLabel for default.
	pfDrawLabel_t    pfDrawLabel;

	// TODO: function to draw complex lines (power line, bridge, etc)

		// Hot spot of phCursor.
	void GetCursorShift (POINT & _ptShift) const;
  private:
	POINT ptCursorShift;
	bool bCursorShiftInitialized;
  public:

		// The pen and hatched bush for transparent polygon mode.
	HPEN             hpenTransparentPolygon;
	HBRUSH           hbrTransparentPolygon;

		// Index of icon in image list.
	size_t           cImageListIndex;

		// Localized type description, if any.
	char *           strTypeNameLocalized;

		// True only for unknown type descriptor.
	bool             bUnknown;

		// The type set which is parent for this type description.
	const CTypeSet * pTypeSet;
		// The ordinal number of this tye description inside the parent type set.
	size_t           cOrdinal;

	bool operator < (const type_desc_t & _other) const {
		return ulType < _other.ulType;
	}

	type_desc_t () {
		::memset (this, 0, sizeof (type_desc_t));
	}
};

	// Placeholder for unknown type.
extern type_desc_t g_tdUnknown;

	//
	// The type set.
	// NOTE: defines also coordinate grid etc.
	//
class CTypeSet {
  public:
	// The type descriptions.
	// NOTE: pTypes[0] is reserved for all unknown types.
	type_desc_t * pTypes;
	// Total number of types.
	size_t        cTypes;

	// Image lists with icons for types.
	HIMAGELIST    GetTypeIcons () const;
  private:
	HIMAGELIST    hilTypeIcons;
	void _InitTypeIcons ();

  public:
	// The unique string ID of the type set.
	const char *  strID;
	// The displayable name.
	const char *  strDisplayName;

	// NOTE: used internally for type localization *.dat files parsing.
	CTypeSet *    pBasicTypeSet;
	bool          bLocalizationIsReady;

	bool          bHasLocalizedTypes;

	// FOR INTERNAL USE ONLY.
	void InitSecondaryAttributes ();
	void DestroySecondaryAttributes ();

	const type_desc_t * GetUnknownTD () const {return & pTypes [0];}

	// Search for type.
	// NOTE: if not found, g_types[0] is returned (which corresponds to "Unknown"). 
	const type_desc_t * GetTypeDesc (USHORT _ushType, USHORT _ushKind) const;

	typedef void (* pfInit_t) ();
	CTypeSet (pfInit_t _pfInit, pfInit_t _pfDestroy);

	const pfInit_t m_pfInit;
	const pfInit_t m_pfDestroy;

	// The linked list of type sets.
	static CTypeSet * s_pFirst;
	CTypeSet * m_pNext;

	static const CTypeSet * FindTypeSet (const char * _strID);
	
	pfConvertTypeSet_t FindConvertTypeSetTo (const CTypeSet * _pTypeSetTo) const;

	//
	// Round coordinates to a specific grid.
	//
	pfGetLatGrid_t  pfGetLatGrid;
	pfRoundPoint_t  pfRoundPoint;
	pfRoundPoints_t pfRoundPoints;
	pfRoundRect_t   pfRoundRect;

	//
	// Type information.
	//
	pfRgnPredicate_t pfIsCity;
	pfRgnPredicate_t pfIsHeight;
	pfRgnPredicate_t pfIsFeature;
	pfRgnPredicate_t pfIsRoad;
	pfRgnPredicate_t pfIsUnpavedRoad;
	pfRgnPredicate_t pfIsHwExit;
	pfRgnPredicate_t pfIsBackground;
	pfRgnPredicate_t pfHasAddress;
	pfRgnPredicate_t pfHasCityAndZip;
	pfRgnPredicate_t pfHasPhone;
	pfRgnPredicate_t pfHasContact;
	pfRgnPredicate_t pfHasDescription;

	//
	// Type set features.
	//

	enum {
		tsfHasCopyright      = 0x01,
		tsfHasElevationUnits = 0x02,
		tsfHasRoadAddress    = 0x04,
	};
	DWORD dwFeatures;

	size_t cMaxBits;
};

inline float DontRoundGrid   (const map_t & _map, size_t _cLevelIdx) {return 0;}
inline void  DontRoundPoint  (const map_t & _map, size_t _cLevelIdx, point_t & _pt) {}
inline void  DontRoundPoints (const map_t & _map, size_t _cLevelIdx, points_t & _points) {}
inline void  DontRoundRect   (const map_t & _map, size_t _cLevelIdx, rect_t & _rect) {}

inline bool RgnPredicateFalse (const rgn_t & _rgn) {return false;}
inline bool RgnPredicateTrue  (const rgn_t & _rgn) {return true;}

	// The default type set (contains just g_tdUnknown).
extern CTypeSet g_tsNull;

# endif // __Types_H_